package org.example.work3.gateway.config;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.cloud.nacos.balancer.NacosBalancer;
import lombok.RequiredArgsConstructor;
import org.example.work3.gateway.property.ServerGrayProperty;
import org.example.work3.gateway.util.VersionUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 版本负载均衡器客户端
 *
 * @author xh
 * @date 2023/04/24
 */
public class VersionLoadBalancerClient implements ReactorServiceInstanceLoadBalancer {

    private ServerGrayProperty serverGrayProperty;

    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public VersionLoadBalancerClient(ServerGrayProperty serverGrayProperty, ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
        this.serverGrayProperty = serverGrayProperty;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier =  serviceInstanceListSupplierProvider.getIfAvailable( NoopServiceInstanceListSupplier::new);

        return supplier.get().next().map(list -> getInstanceResponse(list, serverGrayProperty.getGrayVersion()));
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, String versionValue) {
        //根据版本信息进行过滤
        List<ServiceInstance> chooseInstances = filterList(instances, instance -> versionValue.equals(VersionUtils.getVersion(instance)));
        if (CollUtil.isEmpty(chooseInstances)) {
            System.out.println("没有满足version:" + versionValue + "的服务实例列表，直接使用所有服务实例列表");
            chooseInstances = instances;
        }

        //直接使用Nacos提供的随机+权重算法获取实例列表
        return new DefaultResponse(NacosBalancer.getHostByRandomWeight3(chooseInstances));
    }

    public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
        if (CollUtil.isEmpty(from)) {
            return new ArrayList<>();
        }
        return from.stream().filter(predicate).collect(Collectors.toList());
    }

}
